using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel.Composition;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UCL.Powersource.Analysis;

namespace UCL.Powersource.ViewModels.Analysis
{

    public enum StatisticViewModelTypes
    {
        SingleTeam_SingleTimeFrame,
        SingleTeam_MultipleTimeFrames,
        MultipleTeams_SingleTimeFrame,
        MultipleTeams_MultipleTimeFrames,
    }

    public abstract class StatisticViewModelBase : ViewModelBase, IStatisticViewModel
    {

        public StatisticViewModelBase(StatisticViewModelTypes type, bool supportMultipleStatistics, bool requiresBuild, bool usesNormalizedValues)
        {
            StatisticViewModelType = type;
            IsConsumingActiveStatistic = !supportMultipleStatistics;
            IsBuildRequired = requiresBuild;
            IsConsumingShowNormalized = usesNormalizedValues;
            _RegisteredStatisticsDict = new Dictionary<Guid, IStatistic>();
            RegisteredStatistics = new ReadOnlyDictionary<Guid, IStatistic>(_RegisteredStatisticsDict);
        }

        public StatisticViewModelTypes StatisticViewModelType { get; private set; }

        #region IsConsuming
        public bool IsConsumingMultipleTimeFrames
        {
            get
            {
                return StatisticViewModelType == StatisticViewModelTypes.MultipleTeams_MultipleTimeFrames
                    || StatisticViewModelType == StatisticViewModelTypes.SingleTeam_MultipleTimeFrames;
            }
        }

        public bool IsConsumingMultipleTeamProjectConfigurations
        {
            get
            {
                return StatisticViewModelType == StatisticViewModelTypes.MultipleTeams_MultipleTimeFrames
                    || StatisticViewModelType == StatisticViewModelTypes.MultipleTeams_SingleTimeFrame;
            }
        }

        public bool IsConsumingActiveTimeFrame
        {
            get
            {
                return StatisticViewModelType == StatisticViewModelTypes.SingleTeam_SingleTimeFrame
                    || StatisticViewModelType == StatisticViewModelTypes.MultipleTeams_SingleTimeFrame;
            }
        }
        public bool IsConsumingActiveTeamProjectConfiguration
        {
            get
            {
                return StatisticViewModelType == StatisticViewModelTypes.SingleTeam_SingleTimeFrame
                    || StatisticViewModelType == StatisticViewModelTypes.SingleTeam_MultipleTimeFrames;
            }
        }
        public bool IsConsumingActiveStatistic { get; private set; }
        public bool IsConsumingShowNormalized { get; private set; }
        #endregion

        public IReportingContext ActiveIReportingContext { get; private set; }
        protected IPowersourceExt IPowersourceExt { get; private set; }
        public abstract string Label { get; }
        public abstract string Title { get; }
        public abstract string Description { get; }

        protected virtual void OnActiveTimeFrameChanged() { Log.DebugMethod("{0}", this.GetType().Name); }
        protected virtual void OnActiveTfsTeamProjectConfigurationChanged() { Log.DebugMethod("{0}", this.GetType().Name); }
        protected virtual void OnActiveStatisticChanged() { Log.DebugMethod("{0}", this.GetType().Name); }
        protected virtual void OnShowNormalizedChanged() { Log.DebugMethod("{0}", this.GetType().Name); }
        protected virtual void OnTimeFramesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { Log.DebugMethod("{0} : [{1}]", this.GetType().Name, e.GetNotifyCollectionChangedEventArgsString()); }
        protected virtual void OnTeamProjectConfigurationsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { Log.DebugMethod("{0} : [{1}]", this.GetType().Name, e.GetNotifyCollectionChangedEventArgsString()); }
        protected virtual void OnStatisticsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { Log.DebugMethod("{0} : [{1}]", this.GetType().Name, e.GetNotifyCollectionChangedEventArgsString()); }

        protected virtual void OnIReportingContextChanged() { Log.DebugMethod("{0}", this.GetType().Name); }

        public void Recalculate() { Recalculate_Internal(); RaiseRecalculated(); }

        protected abstract void Recalculate_Internal();
        public abstract bool CanRegisterStatistic(IStatistic statistic);

        public event EventHandler Recalculated;
        protected virtual void RaiseRecalculated()
        {
            if (Recalculated != null) Recalculated(this, EventArgs.Empty);
        }

        protected override bool OnInitializing()
        {
            IPowersourceExt = PowersourceConnector.GetExtensibilityPoint();
            return IPowersourceExt!=null;
        }

        public void OnReportingContextChanged(IReportingContext reportingContext)
        {
            ActiveIReportingContext = reportingContext;
            OnIReportingContextChanged();
            //DisconnectFromActiveIReportingContext();
            //ConnectToReportingContext(reportingContext);
        }

        //private void ConnectToReportingContext(IReportingContext reportingContext)
        //{
        //    if (reportingContext == ActiveIReportingContext && ActiveIReportingContextConnected) return;
        //    if (ActiveIReportingContext != null) DisconnectFromActiveIReportingContext();
        //    ActiveIReportingContext = reportingContext;
        //    if (reportingContext == null) return;
        //    //((INotifyCollectionChanged)(reportingContext.SelectedITfsTeamProjectConfigurations)).CollectionChanged += TeamProjectConfigurations_CollectionChanged;
        //    //((INotifyCollectionChanged)(reportingContext.SelectedITimeFrames)).CollectionChanged += TimeFrames_CollectionChanged;
        //    //((INotifyCollectionChanged)(reportingContext.SelectedIStatistics)).CollectionChanged += Statistics_CollectionChanged;
        //    //((INotifyPropertyChangedEx)(reportingContext)).PropertyChanged += ActiveReportingContext_PropertyChanged;
        //    ActiveIReportingContextConnected = true;
        //    OnIReportingContextConnected();
        //}

        protected override void OnDisposing()
        {
            //DisconnectFromActiveIReportingContext();
            IPowersourceExt = null;
            ActiveIReportingContext = null;

        }

        //private bool ActiveIReportingContextConnected = false;

        //private void DisconnectFromActiveIReportingContext()
        //{
        //    if (ActiveIReportingContext != null && ActiveIReportingContextConnected)
        //    {
        //        OnIReportingContextDisconnecting();
        //        //((INotifyCollectionChanged)(ActiveIReportingContext.SelectedITfsTeamProjectConfigurations)).CollectionChanged -= TeamProjectConfigurations_CollectionChanged;
        //        //((INotifyCollectionChanged)(ActiveIReportingContext.SelectedITimeFrames)).CollectionChanged -= TimeFrames_CollectionChanged;
        //        //((INotifyCollectionChanged)(ActiveIReportingContext.SelectedIStatistics)).CollectionChanged -= Statistics_CollectionChanged;
        //        //((INotifyPropertyChangedEx)(ActiveIReportingContext)).PropertyChanged -= ActiveReportingContext_PropertyChanged;
        //        ActiveIReportingContextConnected = false;
        //    }
        //}

        //void ActiveReportingContext_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        //{
        //    if (IsActivated)
        //    {
        //        if (e.PropertyName == Helpers.PropertyExtensions.GetPropertyName(() => ActiveIReportingContext.ActiveTfsTeamProjectConfiguration))
        //        {
        //            if (IsConsumingActiveTeamProjectConfiguration) OnActiveTfsTeamProjectConfigurationChanged();
        //        }
        //        if (e.PropertyName == Helpers.PropertyExtensions.GetPropertyName(() => ActiveIReportingContext.ActiveTimeFrame))
        //        {
        //            if (IsConsumingActiveTimeFrame) OnActiveTimeFrameChanged();
        //        }
        //        if (e.PropertyName == Helpers.PropertyExtensions.GetPropertyName(() => ActiveIReportingContext.ActiveStatistic))
        //        {
        //            if (IsConsumingActiveStatistic) OnActiveStatisticChanged();
        //        }
        //        if (e.PropertyName == Helpers.PropertyExtensions.GetPropertyName(() => ActiveIReportingContext.ShowNormalized))
        //        {
        //            if (IsConsumingShowNormalized) OnShowNormalizedChanged();
        //        }
        //    }
        //}

        public void ActiveTfsTeamProjectConfigurationChanged()
                {
                    if (IsConsumingActiveTeamProjectConfiguration) OnActiveTfsTeamProjectConfigurationChanged();
                }

        public void ActiveTimeFrameChanged()
                {
                    if (IsConsumingActiveTimeFrame) OnActiveTimeFrameChanged();
                }

        public void ActiveStatisticChanged()
                {
                    if (IsConsumingActiveStatistic) OnActiveStatisticChanged();
                }

        public void ShowNormalizedChanged()
                {
                    if (IsConsumingShowNormalized) OnShowNormalizedChanged();
                }

        public void TimeFramesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (IsActivated && IsConsumingMultipleTimeFrames)
            {
                OnTimeFramesCollectionChanged(sender, e);
            }
        }

        public void TeamProjectConfigurationsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (IsActivated && IsConsumingMultipleTeamProjectConfigurations)
            {
                OnTeamProjectConfigurationsCollectionChanged(sender, e);
            }
        }

        public void StatisticsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (IsActivated && !IsConsumingActiveStatistic)
            {
                OnStatisticsCollectionChanged(sender, e);
            }
        }

        private Dictionary<Guid,IStatistic> _RegisteredStatisticsDict;
        public ReadOnlyDictionary<Guid, IStatistic> RegisteredStatistics { get; private set; }

        #region StatisticResultsTable

        /// <summary>
        /// Field storage for property StatisticResultsTable
        /// </summary>
        private DataTable _StatisticResultsTable = default(DataTable);

        /// <summary>
        /// Property StatisticResultsTable. TODODOC: Insert appropriate summary here
        /// </summary>
        public DataTable StatisticResultsTable
        {
            get { return _StatisticResultsTable; }
            protected set { if (_StatisticResultsTable == value) return; _StatisticResultsTable = value; StatisticResultsTable_RecalculateDependencies(); }
        }

        private void StatisticResultsTable_RecalculateDependencies()
        {
            //Recalculate all properties here

            //NotifyOfPropertyChange is usually placed as last statement - first change all dependencies and then fire property change
            NotifyOfPropertyChange(() => StatisticResultsTable);
        }

        

        #endregion


        #region StatisticResultsTableSet

        /// <summary>
        /// Field storage for property StatisticResultsTableSet
        /// </summary>
        private Tuple<DataTable, DataTable> _StatisticResultsTableSet = default(Tuple<DataTable, DataTable>);

        /// <summary>
        /// Property StatisticResultsTableSet. TODODOC: Insert appropriate summary here
        /// </summary>
        public Tuple<DataTable, DataTable> StatisticResultsTableSet
        {
            get { return _StatisticResultsTableSet; }
            set { if (_StatisticResultsTableSet == value) return; _StatisticResultsTableSet = value; StatisticResultsTableSet_RecalculateDependencies(); }
        }

        private void StatisticResultsTableSet_RecalculateDependencies()
        {
            //Recalculate all properties here

            //NotifyOfPropertyChange is usually placed as last statement - first change all dependencies and then fire property change
            NotifyOfPropertyChange(() => StatisticResultsTableSet);
        }

        private void StatisticResultsTableSet_Recalculate()
        {
            _StatisticResultsTableSet = default(Tuple<DataTable, DataTable>);
            //Insert your code here

            StatisticResultsTableSet_RecalculateDependencies();
        }

        #endregion
	

        public bool TryRegisterStatistic(IStatistic statistic)
        {
            if (CanRegisterStatistic(statistic))
            {
                if (RegisteredStatistics.ContainsKey(statistic.Statistic_Guid))
                {
                    if (RegisteredStatistics[statistic.Statistic_Guid] != statistic)
                    {
                        Debug.Assert(statistic.GetType() != RegisteredStatistics[statistic.Statistic_Guid].GetType(), "2 Instances of the same statistic type found.", "There are most probably 2 instances of the same statistics in statistic manager, or statistic manager collection changed. {0} - {1}", statistic.Statistic_Guid, statistic.GetType().Name);
                        Log.Warn("Ignored statistic {0} [{1} - {2}]. It has the same guid as already registered statistic {3} - {4}", statistic.Name, statistic.Statistic_Guid, statistic.GetType().Name, RegisteredStatistics[statistic.Statistic_Guid].Name, RegisteredStatistics[statistic.Statistic_Guid].GetType().Name);
                        return false;
                    }
                    else return true;
                }
                else
                    _RegisteredStatisticsDict.Add(statistic.Statistic_Guid, statistic);
                return true;
            }
            else return false;
        }

        public bool IsBuildRequired { get; private set; }

        protected void SetActiveStatisticResultsTable()
        {
            if (IsConsumingShowNormalized && ActiveIReportingContext.ShowNormalized)
                StatisticResultsTable = StatisticResultsTableSet.Item2;
            else
                StatisticResultsTable = StatisticResultsTableSet.Item1;
        }
    }
}
